package com.quantum.util
{
	import mx.core.IUID;
	import mx.utils.ObjectUtil;

	public class ObjectUtils
	{
		/**
		 * Tests two objects for equality.
		 *
		 * The following tests are applied in order to test for equality:
		 *
		 * 1. If the equality operator returns true, return true (note, this will return true
		 *    when both operands are null).
		 * 2. Else if both objects are <code>IUID</code>, check uid equality.
		 * 4. Else returns the result of <code>ObjectUtil.compare</code>.
		 *
		 * @param object1
		 *    the first object to compare.
		 * @param object2
		 *    the second object to compare.
		 * @returns <code>true</code> if the objects are the same according to the above
		 *    rules, <code>false</code> otherwise.
		 */
		public static function equalObjects(object1:Object, object2:Object):Boolean
		{
			if (object1 == object2)
			{
				return true;
			}
			if (object1 is IUID && object2 is IUID)
			{
				return IUID(object1).uid == IUID(object2).uid;
			}
			return ObjectUtil.compare(object1, object2) == 0;
		}


		/**
		 * Tests two objects for equality.
		 *
		 * <p/> Returns <code>false</code> if any of the objects is <code>null</code>.
		 *
		 * <p/> Otherwsise calls <code>equalObjects</code> method internally and
		 * returns the result.
		 *
		 * @see #equalObjects()
		 */
//		public static function equalNonNullObjects(object1:Object, object2:Object):Boolean
//		{
//			if (object1 == null || object2 == null)
//			{
//				return false;
//			}
//			
//			return equalObjects(object1, object2);
//		}

		/**
		 * Returns true if the given collection can be iterated over using a "for each" loop.
		 */
//		public static function isIterableCollection(collection:Object):Boolean
//		{
//			return isIndexableOrderedCollection(collection) || collection is Dictionary;
//		}

		/**
		 * Returns true if both the arguments are IUID and their uid properties have the same
		 * value.
		 */
		public static function areIuidEquivalent(object1:Object, object2:Object):Boolean
		{
			if (!(object1 is IUID) || !(object2 is IUID))
			{
				return false;
			}
			return IUID(object1).uid == IUID(object2).uid;
		}

		/**
		 * Copy <code>source</code> into <code>destination</code>. After the copy the
		 * <code>destination</code> dictionary will contain all the keys and value the
		 * <code>source</code> has.
		 *
		 * @param source
		 *    A source dictionary whose key/value pairs to be transfered
		 *
		 * @param destination
		 *    A destination dictionary where to put the key/value pairs from the <code>
		 *    source</code> dictionary.
		 *
		 * @param overwriteDuplicates
		 *    In case of duplicates in the key/value pairs from <code>source</code>
		 *    and <code>destination</code>, should the <code>destination</code> values need
		 *    to be overwritten with the ones from <code>source</code>.
		 */
		public static function copyDictionary(source:Object, destination:Object, overwriteDuplicates:Boolean=true):void
		{
			for (var key:*in source)
			{
				if (!overwriteDuplicates && (destination[key] != null))
				{
					continue;
				}

				destination[key]=source[key];
			}
		}


		/**
		 * Compares two objects based on a property shared by both objects. Objects do not
		 * need to be of the same type. The comparison is performed using
		 * <code>mx.utils.ObjectUtil.compare</code> if both objects have the property to
		 * compare. The return value contract matches that defined by
		 * <code>ObjectUtil.compare</code>. If a single object is null it is considered to
		 * less than (after) the other object.
		 *
		 * @param obj1
		 *       One object
		 *
		 * @param obj2
		 *       Another object
		 *
		 * @return See <code>mx.utils.ObjectUtil.compare</code> for details.
		 *       <ul>
		 *       <li>-1 if obj1 should appear before obj2 in ascending order.</li>
		 *       <li>0 if obj1 equals obj2.</li>
		 *       <li>1 if obj1 should appear after obj2 in ascending order.</li>
		 *       </ul
		 *
		 * @throws Error If one or both objects do not have a property named
		 *       <code>propertyName</code>.
		 */
		public static function compareProperty(obj1:Object, obj2:Object, propertyName:String):int
		{
			if (obj1 == obj2)
			{
				return 0;
			}
			if (obj1 == null)
			{
				return 1;
			}
			if (obj2 == null)
			{
				return -1;
			}
			if (!obj1.hasOwnProperty(propertyName) || !obj2.hasOwnProperty(propertyName))
			{
				throw new Error("Property comparator invoked with a type that does not have " + "the property '" + propertyName + "' to compare.");
			}
			return ObjectUtil.compare(obj1[propertyName], obj2[propertyName]);
		}
	}
}